/**
 **************************************************************************
 * @file     main.c
 * @brief    main program
 **************************************************************************
 *                       Copyright notice & Disclaimer
 *
 * The software Board Support Package (BSP) that is made available to
 * download from Artery official website is the copyrighted work of Artery.
 * Artery authorizes customers to use, copy, and distribute the BSP
 * software and its related documentation for the purpose of design and
 * development in conjunction with Artery microcontrollers. Use of the
 * software is governed by this copyright notice and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
 * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
 * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
 * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
 * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 **************************************************************************
 */

#include "at32f413_clock.h"
#include <string.h>
#include "bootloader.h"
#include "at32_mcu_info.h"
#include "zino_products.h"
// #include <stdio.h>
/** @addtogroup AT32F421_periph_examples
 * @{
 */

/** @addtogroup 421_USART_transfer_by_dma_interrupt USART_transfer_by_dma_interrupt
 * @{
 */

const firmware_info_t zino_firemware_info __attribute__((section("firemware_info"))) = {
	.name = "FUNPLAY_DRONE_V5.0",
	.version = 0x00000001,
	.magic = FLASH_FW_MAGIC,
	.start_addr = 0x08004000,
	.pid = ZINO_FUNPLAY_DRONE_V5_0_PID,
	.date = DATE2INT(2025, 9, 22),
	.DeviceID = AT32F421C8T7_64KB_LQFP48,

};

#define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
#define USART2_TX_BUFFER_SIZE FRAME_DATA_SIZE + 24
#define USART1_TX_BUFFER_SIZE FRAME_DATA_SIZE + 24

uint8_t usart2_tx_buffer[USART2_TX_BUFFER_SIZE];
uint8_t usart2_rx_buffer[USART1_TX_BUFFER_SIZE];
// uint8_t usart1_tx_buffer[USART2_TX_BUFFER_SIZE];
// uint8_t usart1_rx_buffer[USART2_TX_BUFFER_SIZE];
volatile uint8_t usart2_tx_dma_status = 0;
volatile uint8_t usart2_rx_dma_status = 0;
uint16_t usart2_rxlen = 0;
// volatile uint8_t usart1_tx_dma_status = 0;
// volatile uint8_t usart1_rx_dma_status = 0;
int uart2_put(uint8_t *buf, uint16_t len);
int uart2_get(uint8_t *buf);

int uart1_put(uint8_t *buf, uint16_t len);
int uart1_get(uint8_t *buf);

/**
 * @brief  config usart2 and usart1
 * @param  none
 * @retval none
 */
void usart_configuration(void)
{
	// gpio_init_type gpio_init_struct;

	// /* enable the usart2 and gpio clock */
	// crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
	// crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

	// gpio_default_para_init(&gpio_init_struct);
	// /* configure the usart2 tx/rx pin */
	// gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	// gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	// gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	// gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3;
	// gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	// gpio_init(GPIOA, &gpio_init_struct);

	// /* config usart2 iomux */
	// gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_1);
	// gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_1);

	// /* configure usart2 param */
	// usart_init(USART2, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);
	// usart_transmitter_enable(USART2, TRUE);
	// usart_receiver_enable(USART2, TRUE);
	// usart_dma_transmitter_enable(USART2, TRUE);
	// usart_dma_receiver_enable(USART2, TRUE);
	// usart_enable(USART2, TRUE);
	// nvic_irq_enable(USART2_IRQn, 0, 0);
	// usart_interrupt_enable(USART2, USART_IDLE_INT, TRUE);


	gpio_init_type gpio_init_struct;

	/* enable the usart1 and gpio clock */
	crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

	gpio_default_para_init(&gpio_init_struct);
	/* configure the usart1 tx pin */
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	gpio_init_struct.gpio_pins = GPIO_PINS_9;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init(GPIOA, &gpio_init_struct);


	/* configure the usart1 rx pin */
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
	gpio_init_struct.gpio_pins = GPIO_PINS_10;
	gpio_init_struct.gpio_pull = GPIO_PULL_UP;
	gpio_init(GPIOA, &gpio_init_struct);

	/* configure usart1 param */
	usart_init(USART1, 1500000, USART_DATA_8BITS, USART_STOP_1_BIT);
	usart_transmitter_enable(USART1, TRUE);
	usart_receiver_enable(USART1, TRUE);
	usart_dma_transmitter_enable(USART1, TRUE);
	usart_dma_receiver_enable(USART1, TRUE);
	usart_enable(USART1, TRUE);
	nvic_irq_enable(USART1_IRQn, 0, 0);
	usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);

}
// void rled(confirm_state new_state)
// {
// 	if (new_state)
// 	{
// 		gpio_bits_reset(GPIOB, GPIO_PINS_0);
// 	}
// 	else
// 	{
// 		gpio_bits_set(GPIOB, GPIO_PINS_0);
// 	}
// }
// void gled(confirm_state new_state)
// {
	// if (new_state)
	// {
	// 	gpio_bits_reset(GPIOA, GPIO_PINS_10);
	// }
	// else
	// {
	// 	gpio_bits_set(GPIOA, GPIO_PINS_10);
	// }
// }
// void bled(confirm_state new_state)
// {
	// if (new_state)
	// {
	// 	gpio_bits_reset(GPIOA, GPIO_PINS_11);
	// }
	// else
	// {
	// 	gpio_bits_set(GPIOA, GPIO_PINS_11);
	// }
// }
// void power_ctrl(confirm_state new_state)
// {
	// if (new_state)
	// {
	// 	gpio_bits_set(GPIOA, GPIO_PINS_5);
	// }
	// else
	// {
	// 	gpio_bits_reset(GPIOA, GPIO_PINS_5);
	// }
// }
// void pwr_5V_ctrl(confirm_state new_state)
// {
	// if (new_state)
	// {
	// 	gpio_bits_set(GPIOB, GPIO_PINS_2);
	// }
	// else
	// {
	// 	gpio_bits_reset(GPIOB, GPIO_PINS_2);
	// }
// }
/**
 * @brief  config dma for usart2 and usart1
 * @param  none
 * @retval none
 */
void dma_configuration(void)
{
	dma_init_type dma_init_struct;

	/* enable dma1 clock */
	crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);

	/* dma1 channel4 for usart1 tx configuration */
	dma_reset(DMA1_CHANNEL4);
	dma_default_para_init(&dma_init_struct);
	dma_init_struct.buffer_size = 0;
	dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
	dma_init_struct.memory_base_addr = (uint32_t)usart2_tx_buffer;
	dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
	dma_init_struct.memory_inc_enable = TRUE;
	dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
	dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
	dma_init_struct.peripheral_inc_enable = FALSE;
	dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
	dma_init_struct.loop_mode_enable = FALSE;
	dma_init(DMA1_CHANNEL4, &dma_init_struct);

	/* enable transfer full data interrupt */
	dma_interrupt_enable(DMA1_CHANNEL4, DMA_FDT_INT, TRUE);

	/* dma1 channel4 interrupt nvic init */
	nvic_irq_enable(DMA1_Channel4_IRQn, 0, 0);

	/* dma1 channel5 for usart2 rx configuration */
	dma_reset(DMA1_CHANNEL5);
	dma_default_para_init(&dma_init_struct);
	dma_init_struct.buffer_size = USART2_TX_BUFFER_SIZE;
	dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
	dma_init_struct.memory_base_addr = (uint32_t)usart2_rx_buffer;
	dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
	dma_init_struct.memory_inc_enable = TRUE;
	dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
	dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
	dma_init_struct.peripheral_inc_enable = FALSE;
	dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
	dma_init_struct.loop_mode_enable = TRUE;
	dma_init(DMA1_CHANNEL5, &dma_init_struct);

	/* enable transfer full data interrupt */
	// dma_interrupt_enable(DMA1_CHANNEL5, DMA_FDT_INT, TRUE);

	/* dma1 channel5 interrupt nvic init */
	nvic_irq_enable(DMA1_Channel5_IRQn, 0, 0);

	dma_channel_enable(DMA1_CHANNEL5, TRUE); /* usart2 rx begin dma receiving */
	// dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */

}


// char *ltoa(long value, char *string, int radix)
// {
// 	char tmp[33];
// 	char *tp = tmp;
// 	long i;
// 	unsigned long v;
// 	int sign;
// 	char *sp;

// 	if (string == NULL)
// 	{
// 		return 0;
// 	}

// 	if (radix > 36 || radix <= 1)
// 	{
// 		return 0;
// 	}

// 	sign = (radix == 10 && value < 0);
// 	if (sign)
// 	{
// 		v = -value;
// 	}
// 	else
// 	{
// 		v = (unsigned long)value;
// 	}

// 	while (v || tp == tmp)
// 	{
// 		i = v % radix;
// 		v = v / radix;
// 		if (i < 10)
// 			*tp++ = i + '0';
// 		else
// 			*tp++ = i + 'a' - 10;
// 	}

// 	sp = string;

// 	if (sign)
// 		*sp++ = '-';
// 	while (tp > tmp)
// 		*sp++ = *--tp;
// 	*sp = 0;

// 	return string;
// }
// void softDelay(uint32_t ms)
// {
// 	for (uint16_t i = 0; i < ms; i++)
// 		for (uint16_t j = 0; j < 50000; j++)
// 			for (uint16_t k = 0; k < 5000; k++)
// 			{
// 			}
// }
void gpio_config(void)
{
	gpio_init_type gpio_init_struct;

	/* enable the gpioa clock */
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

	/* set default parameter */
	gpio_default_para_init(&gpio_init_struct);

	/* configure the gpio */
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_pins = GPIO_PINS_10 | GPIO_PINS_11;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init(GPIOA, &gpio_init_struct);
	gpio_init_struct.gpio_pins = GPIO_PINS_0;
	gpio_init(GPIOB, &gpio_init_struct);

	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pins = GPIO_PINS_2;
	gpio_init(GPIOB, &gpio_init_struct);

	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pins = GPIO_PINS_5;
	gpio_init(GPIOA, &gpio_init_struct);
}

void at32_flash_read(uint32_t address, uint8_t *buffer, uint32_t len)
{
	memcpy(buffer, (void *)address, len);
}
void at32_flash_write(uint32_t address, uint8_t *buffer, uint32_t len)
{
	flash_unlock();
	while (len--)
	{
		flash_byte_program(address++, *buffer++);
	}
	flash_lock();
}
typedef void (*iapfun)(void);
volatile iapfun jump2app;
void IAP_Load_APP(uint32_t appxaddr)
{
	SysTick->CTRL = 0; // stop systick
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, FALSE);
	crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, FALSE);
	crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, FALSE);
	crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, FALSE);
	nvic_irq_disable(DMA1_Channel4_IRQn);
	nvic_irq_disable(DMA1_Channel5_IRQn);
	__disable_irq();
	USART1->sts = 0;
	dma_reset(DMA1_CHANNEL4);
	dma_reset(DMA1_CHANNEL5);
	usart_reset(USART1);
	jump2app = (iapfun)(*(volatile uint32_t *)(appxaddr + 4)); // 用户代码区第二个字为程序开始地址(复位地址)
	__set_MSP(*(volatile uint32_t *)appxaddr);
	__set_PSP(*(volatile uint32_t *)appxaddr); // 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
	__set_CONTROL(0);
	jump2app(); // 跳转到APP.
}
void at32_flash_sector_erase(uint32_t address)
{
	flash_sector_erase(address);
}
bl_info_t bl_info;
void usart2_rx_test(void)
{
	uint8_t buf[USART2_TX_BUFFER_SIZE];
	uint16_t getLen = 0;
	getLen = uart2_get(buf);

	if (getLen > 0)
	{

		uart2_put(buf, getLen);
	}
}
void bl_init(bl_info_t *bl)
{
	bl->DeviceID = AT32F413RCT7_256KB_LQFP64;
	bl->fw_info.pid = PID2INT(0, 0, 0, 0);
	bl->version = VESION2INT(2, 0, 0, 0);
	bl->appAddr = FLASH_APP_ADDR;
	bl->appSize = FLASH_APP_SIZE;
	bl->fwInfoAddr = FLASH_FWINFO_ADDR;
	bl->sectorSize = FLASH_SectorSize;
	bl->sectorCount = FLASH_SECTOR_COUNT;
	bl->read = uart1_get;
	bl->write = uart1_put;
	bl->millis = millis;
	bl->flashLock = flash_lock;
	bl->flashUnlock = flash_unlock;
	bl->flashSectorErase = at32_flash_sector_erase;
	bl->flashRead = at32_flash_read;
	bl->flashWrite = at32_flash_write;
	bl->jumpToAddr = IAP_Load_APP;
	bl->reset = nvic_system_reset;
}
/**
 * @brief  main function.
 * @param  none
 * @retval none
 */
int main(void)
{
	system_clock_config();

	gpio_config();
	nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
	nvic_irq_enable(SysTick_IRQn, 0, 0);
	usart_configuration();
	dma_configuration();
	systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);
	SysTick_Config(SystemCoreClock / 1000);

	// pwr_5V_ctrl(1);
	// power_ctrl(1);
	// bled(1);
	// gled(1);

	// delay_ms(1000);
	// /* wait dma transmission complete */
	// while((usart2_tx_dma_status == 0) || (usart2_rx_dma_status == 0) || (usart1_tx_dma_status == 0) || (usart1_rx_dma_status == 0));

	// static uint32_t t2 = 0;
	// bled(0);
	// gled(0);
	// uint8_t flag = 1;


	bl_init(&bl_info);
	while (1)
	{
		// /* compare data buffer */
		// if (millis() > (t2 + 100))
		// {
			// t2 = millis();
			// flag = !flag;
			// rled(flag);
			// bled(flag);
			// gled(!flag);

			// uart2_put("hello world\r\n", 13);
			// }
			// usart2_rx_test();
		bootloader_handle(&bl_info);
	}
}
int uart2_put(uint8_t *buf, uint16_t len)
{
	while (usart2_tx_dma_status == 1)
		;
		// gled(1);
	memcpy(usart2_tx_buffer, buf, len);
	usart2_tx_dma_status = 1;
	dma_data_number_set(DMA1_CHANNEL4, len);
	dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */
	return len;
}
int uart2_get(uint8_t *buf)
{
	if (usart2_rxlen != 0)
	{
		uint16_t len = usart2_rxlen;
		// uint16_t len = dma_data_number_get(DMA1_CHANNEL5);
		memcpy(buf, usart2_rx_buffer, len);
		usart2_rxlen = 0;

		// bled(0);
		return len;
	}
	return 0;
}
int uart1_put(uint8_t *buf, uint16_t len)
{
	while (usart2_tx_dma_status == 1)
		;
		// gled(1);
	memcpy(usart2_tx_buffer, buf, len);
	usart2_tx_dma_status = 1;
	dma_data_number_set(DMA1_CHANNEL4, len);
	dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */
	return len;
}
int uart1_get(uint8_t *buf)
{
	if (usart2_rxlen != 0)
	{
		int len = usart2_rxlen;
		// uint16_t len = dma_data_number_get(DMA1_CHANNEL5);
		memcpy(buf, usart2_rx_buffer, len);
		usart2_rxlen = 0;

		// bled(0);
		return len;
	}
	return 0;
}
void USART1_IRQHandler(void)
{
	if (usart_interrupt_flag_get(USART1, USART_IDLEF_FLAG) != RESET)
	{
		usart_flag_clear(USART1, USART_IDLEF_FLAG);
		usart2_rx_dma_status = 1;
		dma_channel_enable(DMA1_CHANNEL5, FALSE);
		usart2_rxlen = USART2_TX_BUFFER_SIZE - dma_data_number_get(DMA1_CHANNEL5);
		dma_data_number_set(DMA1_CHANNEL5, USART2_TX_BUFFER_SIZE);
		dma_channel_enable(DMA1_CHANNEL5, TRUE);
		// bled(1);
	}
}
/**
 * @}
 */

/**
 * @}
 */
